package xyz.thoughtset.viewer.common.envvar.service;

import cn.hutool.core.collection.ConcurrentHashSet;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import jakarta.annotation.PostConstruct;
import lombok.SneakyThrows;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xyz.thoughtset.viewer.common.crud.core.service.BaseServiceImpl;
import xyz.thoughtset.viewer.common.envvar.annotation.EnvPropSign;
import xyz.thoughtset.viewer.common.envvar.constants.EnvVarDataTypeConstant;
import xyz.thoughtset.viewer.common.envvar.dao.EnvVarsDao;
import xyz.thoughtset.viewer.common.envvar.entity.EnvVars;
import xyz.thoughtset.viewer.common.envvar.entity.EnvVars;
import xyz.thoughtset.viewer.common.envvar.factory.EnvPropSignFactory;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Service
public class EnvVarsServiceImpl extends BaseServiceImpl<EnvVarsDao, EnvVars> implements EnvVarsService {
    private static final String TARGET_DATA_KEY = "pbo";
    private static final ConcurrentHashMap<String,EnvVars> VAR_CACHE = new ConcurrentHashMap<>();
    private static final ConcurrentHashMap<String, ConcurrentHashSet<EnvVars>> VAR_SUB_CACHE = new ConcurrentHashMap<>();

    @Autowired
    private EnvPropSignFactory envSignFactory;

    @PostConstruct
    public void init(){
        List<EnvVars> list = baseMapper.selectList(new QueryWrapper<>());
        list.parallelStream().map(ele -> {
            ele.setBody(envSignFactory.loadData(ele));
            putCache(ele);
            return ele;
        }).collect(Collectors.toList());
    }

    @SneakyThrows
    @Override
    public Object saveData(LinkedHashMap<String, Object> baseMap) {
        Object targetData = baseMap.remove(TARGET_DATA_KEY);
        EnvVars data = convertValue(baseMap);
        String topic = data.getTopic();
        if (EnvVarDataTypeConstant.OBJ.equals(data.getType())) {
            targetData = envSignFactory.getTargetData(topic, targetData);
        }
        data.setPayload(mapper.writeValueAsString(targetData));
        if (envSignFactory.getSignInfo(topic).single()){
            data.setId(topic);
        }
        saveOrUpdate(data);
        putCache(data);
        return data;
    }

    @Override
    public EnvVars selectDetail(String pkey) {
        EnvVars envVars = super.selectDetail(pkey);
        if (envVars != null) {
            envVars.setBody(envSignFactory.loadData(envVars));
            putCache(envVars);
        }
        return envVars;
    }

    @Override
    public EnvVars getEnvVars(String varId) {
        return findCache(varId);
    }

    @Override
    public Object loadData(String varId) {
        EnvVars envVars = findCache(varId);
        return Objects.isNull(envVars)?null:envVars.getPbo();
    }

    @SneakyThrows
    @Override
    public <T> T loadSingleData(Class<T> tarType) {
//        QueryWrapper<EnvVars> queryWrapper = new QueryWrapper<>();
//        queryWrapper.lambda().eq(EnvVars::getTopic,tarType.getSimpleName());
        String key = tarType.getSimpleName();
        EnvPropSign sign = envSignFactory.getSignInfo(tarType);
        T result = null;
        if (sign.single()){
            result = (T) loadData(key);
        }else {
            QueryWrapper<EnvVars> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda()
                    .eq(EnvVars::getTopic,key)
                    .orderByDesc(EnvVars::getUpdatedAt)
                    .orderByDesc(EnvVars::getId)
                    .last("LIMIT 1");
            EnvVars vars = baseMapper.selectOne(queryWrapper,false);
            result = (T) envSignFactory.loadData(vars);
        }

        if (Objects.isNull(result)) {
            result = tarType.getDeclaredConstructor().newInstance();
        }
        return result;
    }

    @Override
    public Set<EnvVars> getObjListWithTopic(String topic) {
        return VAR_SUB_CACHE.get(topic);
    }


    private synchronized EnvVars putCache(EnvVars vars) {
        String key = vars.getId();
        VAR_CACHE.put(key, vars);
        ConcurrentHashSet set = VAR_SUB_CACHE.computeIfAbsent(vars.getTopic(),k -> new ConcurrentHashSet<>());
        set.remove(vars);
        set.add(vars);
        return vars;
    }
    private EnvVars findCache(String key) {
        EnvVars envVars = VAR_CACHE.get(key);
        if (envVars != null) {
            return envVars;
        }
        envVars = baseMapper.selectById(key);
        if (envVars != null) {
            envVars.setBody(envSignFactory.loadData(envVars));
            putCache(envVars);
        }
        return envVars;
    }

}
